<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务，帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件，不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);

namespace app\store\model;

use app\common\enum\order\OrderStatus as OrderStatusEnum;
use app\store\model\User as UserModel;
use app\common\model\OrderRefund as OrderRefundModel;
use app\common\model\OrderGoods as OrderGoodsModel;
use app\common\enum\order\refund\RefundType as RefundTypeEnum;
use app\common\enum\order\refund\AuditStatus as AuditStatusEnum;
use app\common\enum\order\refund\RefundStatus as RefundStatusEnum;
use app\common\service\Message as MessageService;
use app\common\service\order\Refund as RefundService;
use app\store\service\store\User as StoreUserService;


/**
 * 售后单模型
 * Class OrderRefund
 * @package app\api\model
 */
class OrderRefund extends OrderRefundModel
{
    /**
     * 获取售后单列表
     * @param array $param
     * @return mixed
     */
    public function getList(array $param = [])
    {
        // 检索查询条件
        $filter = $this->getFilter($param);
        // 获取列表数据
        return $this->alias('refund')
            ->field('refund.*, order.order_no')
            ->with(['orderGoods.image', 'orderData', 'user.avatar'])
            ->join('order', 'order.order_id = refund.order_id')
            ->join('user', 'user.user_id = order.user_id')
            ->where($filter)
            ->order(['refund.create_time' => 'desc', 'refund.' . $this->getPk()])
            ->paginate(10);
    }

    /**
     * 获取售后单详情
     * @param int $orderRefundId
     * @return OrderRefund|false|null
     */
    public function getDetail(int $orderRefundId)
    {
        return static::detail($orderRefundId, [
            'orderData', 'images.file', 'orderGoods.image', 'express', 'address', 'user'
        ]) ?: false;
    }

    /**
     * 检索查询条件
     * @param array $param
     * @return array
     */
    private function getFilter(array $param = []): array
    {
        // 默认查询条件
        $params = $this->setQueryDefaultValue($param, [
            'searchType' => '',     // 关键词类型 (10订单号 20会员昵称 30会员ID)
            'searchValue' => '',    // 关键词内容
            'refundType' => -1,      // 售后类型
            'refundStatus' => -1,    // 售后单状态
            'betweenTime' => [],    // 申请时间
        ]);
        // 检查查询条件
        $filter = [];
        // 关键词
        if (!empty($params['searchValue'])) {
            $searchWhere = [
                10 => ['order.order_no', 'like', "%{$params['searchValue']}%"],
                20 => ['user.nick_name', 'like', "%{$params['searchValue']}%"],
                30 => ['order.user_id', '=', (int)$params['searchValue']]
            ];
            array_key_exists($params['searchType'], $searchWhere) && $filter[] = $searchWhere[$params['searchType']];
        }
        // 起止时间
        if (!empty($params['betweenTime'])) {
            $times = between_time($params['betweenTime']);
            $filter[] = ['refund.create_time', '>=', $times['start_time']];
            $filter[] = ['refund.create_time', '<', $times['end_time'] + 86400];
        }
        // 售后类型
        $params['refundType'] > -1 && $filter[] = ['refund.type', '=', (int)$params['refundType']];
        // 处理状态
        $params['refundStatus'] > -1 && $filter[] = ['refund.status', '=', (int)$params['refundStatus']];
        return $filter;
    }

    /**
     * 商家审核
     * @param array $data
     * @return bool
     */
    public function audit(array $data): bool
    {
        if ($data['audit_status'] == AuditStatusEnum::REJECTED && empty($data['refuse_desc'])) {
            $this->error = '请输入拒绝原因';
            return false;
        }
        if ($data['audit_status'] == AuditStatusEnum::REVIEWED && empty($data['address_id'])) {
            $this->error = '请选择退货地址';
            return false;
        }
        $this->transaction(function () use ($data) {
            // 拒绝申请, 标记售后单状态为已拒绝
            $data['audit_status'] == AuditStatusEnum::REJECTED && $data['status'] = RefundStatusEnum::REJECTED;
            // 同意换货申请, 标记售后单状态为已完成
            $data['audit_status'] == AuditStatusEnum::REVIEWED && $this['type'] == RefundTypeEnum::EXCHANGE && $data['status'] = RefundStatusEnum::COMPLETED;
            $data['admin_id'] = StoreUserService::getLoginUserId();
            // 更新退款单状态
            $this->save($data);
            // 同意售后申请, 记录退货地址
            if ($data['audit_status'] == AuditStatusEnum::REVIEWED) {
                (new OrderRefundAddress)->add((int)$this['order_refund_id'], (int)$data['address_id']);
            }
            // 订单详情
            $order = Order::detail($this['order_id'],['goods']);
            // 发送消息通知
            $data['order_id'] = $order['order_id'];
            $data['type'] = $this['type'];
            $data['store_id'] = $this['store_id'];
            $data['user_id'] = $order['user_id'];
            $data['order_goods_id'] = $this['order_goods_id'];
            $data['order_refund_id'] = $this['order_refund_id'];
            if ($data['audit_status'] == AuditStatusEnum::REJECTED) {
                $refuse_desc = '';
                if($this['refuse_desc']){
                    $refuse_desc = ',' . $this['refuse_desc'];
                }
                $data['check_result'] = $data['type'] == 10 ? '拒绝退货' : '拒绝换货';
            }
            if ($data['audit_status'] == AuditStatusEnum::REVIEWED) {
                $data['check_result']  = $data['type'] == 10 ? '同意退货' : '同意换货';
            }
            //小程序发订阅消息
            MessageService::WxMessageOrderSaleService('order.messagewx', $data);
            /*MessageService::send('order.refund', [
                'refund' => $this,                  // 退款单信息
                'order_no' => $order['order_no']    // 订单信息
            ], $this['store_id']);*/
        });
        return true;
    }

    /**
     * 确认收货并退款
     * @param array $data
     * @return bool
     */
    public function receipt(array $data): bool
    {

        // 订单详情
        $order = Order::detail($this['order_id']);
        if ($data['refund_money'] > min($order['pay_price'], $this['orderGoods']['total_pay_price'])) {
            $this->error = '退款金额不能大于商品实付款金额';
            return false;
        }
        //处理订单商品都退款了，订单状态已完成
        $OrderGoodsModel = new OrderGoodsModel();
        $orderGoods = $OrderGoodsModel->with(['refund'])
            ->where(['order_id'=>$this['order_id']])
            ->select();
        foreach ($orderGoods as $key=>$value){
            if(!empty($value['refund']) && $value['refund']['order_refund_id'] == $this['order_refund_id']){
                $order['bd_type'] = $value['bd_type'];//当前退款商品
                $order['pay_cash'] = $value['pay_cash'];
                $order['deduction_value'] = $value['deduction_value'];
            }
            if(!empty($value['refund']) && (($value['refund']['status'] == 20 && $value['refund']['type'] == 10) || $value['refund']['order_refund_id'] == $this['order_refund_id'])){
                unset($orderGoods[$key]);//删除已退款和即将退款的商品
            }
        }

        // 事务处理
        $this->transaction(function () use ($order, $data,$orderGoods) {
            if(empty($orderGoods)){//所有商品都退款了订单状态改成已完成
                Order::update(['order_status' => OrderStatusEnum::COMPLETED], ['order_id' => $this['order_id']]);
            }
            // 更新售后单状态
            $this->save([
                'refund_money' => $data['refund_money'],
                'is_receipt' => 1,
                'status' => RefundStatusEnum::COMPLETED,
                'admin_id' => StoreUserService::getLoginUserId()
            ]);
            // 消减用户的实际消费金额
            // 条件：判断订单是否已结算
            if ($order['is_settled'] == true) {
                (new UserModel)->setDecUserExpend($order['user_id'], $data['refund_money']);
            }
            $order['is_bd'] = $this['orderGoods']['is_bd'];//退款的商品是否支持邦豆支付
            // 执行原路退款
            (new RefundService)->execute($order, (string)$data['refund_money']);
            // 发送消息通知
            $message['store_id'] = $order['store_id'];
            $message['order_no'] = $order['order_no'];
            $message['user_id'] = $order['user_id'];
            $message['total_pay_price'] = $data['refund_money'];
            $message['refund_reason'] = '用户申请退货退款';
            $message['order_refund_id'] = $this['order_refund_id'];
            $message['goods_name'] = $this['orderGoods']['goods_name'];
            $message['type'] = $this['type'];
            MessageService::WxMessageOrderRefund('order.messagewx', $message);
            /*MessageService::send('order.refund', [
                'refund' => $this,                  // 退款单信息
                'order_no' => $order['order_no'],   // 订单信息
            ], $this['store_id']);*/
        });
        return true;
    }

    /**
     * 获取待处理售后单数量
     * @return int
     */
    public function getRefundTotal()
    {
        return $this->where('status', '=', RefundStatusEnum::NORMAL)->count();
    }

    /**
     * 后台更新退货物流
     * @param array $data
     * @return bool
     */
    public function updateExpress(array $data): bool
    {
        // 更新退款单状态
        $data['is_user_send'] = 1;
        $data['send_time'] = time();
        $data['admin_id'] = StoreUserService::getLoginUserId();
        $this->save($data);
        return true;
    }

    /**
     * 商家缺货退款
     * @param $orderGoodId
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function goodRefund($orderGoodId): bool
    {
        $orderGoodInfo = OrderGoodsModel::detail($orderGoodId);
        //处理订单商品都退款了，订单状态已完成
        $OrderGoodsModel = new OrderGoodsModel();
        $orderGoods = $OrderGoodsModel->with(['refund'])
            ->where(['order_id'=>$orderGoodInfo['order_id']])
            ->select()->toArray();
        foreach ($orderGoods as $key=>$value){
            if($value['order_goods_id'] == $orderGoodId){
                unset($orderGoods[$key]);//删除当前退款商品
            }
            if(!empty($value['refund']) && ($value['refund']['status'] == 20 && $value['refund']['type'] == 30)){
                unset($orderGoods[$key]);//删除缺货已退款商品
            }
        }

        // 事务处理
        $this->transaction(function () use ($orderGoodInfo,$orderGoods) {
            $orderInfo = Order::detail($orderGoodInfo['order_id']);
            $orderGoodInfo['pay_type'] = $orderInfo['pay_type'];
            $orderGoodInfo['transaction_id'] = $orderInfo['transaction_id'];
            $orderGoodInfo['order_no'] = $orderInfo['order_no'];
            if(empty($orderGoods)){//所有商品都退款了订单状态改成已完成
                Order::update(['order_status' => OrderStatusEnum::CANCELLED], ['order_id' => $orderGoodInfo['order_id']]);
            }
            $this->save([
                'order_goods_id' => $orderGoodInfo['order_goods_id'],
                'order_id' => $orderGoodInfo['order_id'],
                'user_id' => $orderGoodInfo['user_id'],
                'refund_money'=>$orderGoodInfo['total_pay_price'],
                'type' => RefundTypeEnum::OUTOFSTOCK,
                'apply_desc' => '商家缺货退款',
                'audit_status' => AuditStatusEnum::REVIEWED,
                'status' => RefundStatusEnum::COMPLETED,
                'store_id' => self::$storeId,
                'admin_id' => StoreUserService::getLoginUserId()
            ]);
            // 执行原路退款
            (new RefundService)->execute($orderGoodInfo, (string)$orderGoodInfo['total_pay_price']);
            $orderGoodInfo['refund_reason'] = '商家缺货退款';
            $orderGoodInfo['order_refund_id'] = $this['order_refund_id'];
            $orderGoodInfo['type'] = RefundTypeEnum::OUTOFSTOCK;
            MessageService::WxMessageOrderRefund('order.messagewx', $orderGoodInfo->toArray());
            // 发送消息通知
            /*MessageService::send('order.refund', [
                'refund' => $this,                  // 退款单信息
                'order_no' => $order['order_no'],   // 订单信息
            ], $this['store_id']);*/
        });
        return true;
    }
}
